/*
REWRITTEN FROM SCRATCH BY PUSSYWIZARD, IT OWNS NOW!
*/

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "forge_of_souls.h"
#include "Player.h"

class instance_forge_of_souls : public InstanceMapScript
{
public:
	instance_forge_of_souls() : InstanceMapScript("instance_forge_of_souls", 632) { }

	InstanceScript* GetInstanceScript(InstanceMap *map) const
	{
		return new instance_forge_of_souls_InstanceScript(map);
	}

	struct instance_forge_of_souls_InstanceScript : public InstanceScript
	{
		instance_forge_of_souls_InstanceScript(Map* map) : InstanceScript(map) {}

		uint32 m_auiEncounter[MAX_ENCOUNTER];
		TeamId teamIdInInstance;
		std::string str_data;
		uint64 NPC_BronjahmGUID;
		uint64 NPC_DevourerGUID;

		uint64 NPC_LeaderFirstGUID;
		uint64 NPC_LeaderSecondGUID;
		uint64 NPC_GuardFirstGUID;
		uint64 NPC_GuardSecondGUID;

		void Initialize()
		{
			memset(&m_auiEncounter, 0, sizeof(m_auiEncounter));
			teamIdInInstance = TEAM_NEUTRAL;
			NPC_BronjahmGUID = 0;
			NPC_DevourerGUID = 0;

			NPC_LeaderFirstGUID = 0;
			NPC_LeaderSecondGUID = 0;
			NPC_GuardFirstGUID = 0;
			NPC_GuardSecondGUID = 0;
		}

		bool IsEncounterInProgress() const
		{
			for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
				if (m_auiEncounter[i] == IN_PROGRESS) return true;

			return false;
		}

		void OnPlayerEnter(Player* /*plr*/)
		{
			// this will happen only after crash and loading the instance from db
			if (m_auiEncounter[0] == DONE && m_auiEncounter[1] == DONE && (!NPC_LeaderSecondGUID || !instance->GetCreature(NPC_LeaderSecondGUID)))
			{
				Position pos = {5658.15f, 2502.564f, 708.83f, 0.885207f};
				instance->SummonCreature(NPC_SYLVANAS_PART2, pos);
			}
		}

		void OnCreatureCreate(Creature* creature)
		{
			if (teamIdInInstance == TEAM_NEUTRAL)
			{
				Map::PlayerList const &players = instance->GetPlayers();
				if (!players.isEmpty())
					if (Player* player = players.begin()->GetSource())
						teamIdInInstance = player->GetTeamId();
			}

			switch (creature->GetEntry())
			{
				case NPC_BRONJAHM:
					NPC_BronjahmGUID = creature->GetGUID();
					break;
				case NPC_DEVOURER:
					NPC_DevourerGUID = creature->GetGUID();
					break;
				case NPC_SYLVANAS_PART1:
					if (teamIdInInstance == TEAM_ALLIANCE)
						creature->UpdateEntry(NPC_JAINA_PART1);
					NPC_LeaderFirstGUID = creature->GetGUID();

					if (m_auiEncounter[0] == DONE && m_auiEncounter[1] == DONE)
						creature->SetVisible(false);
					break;
				case NPC_SYLVANAS_PART2:
					if (teamIdInInstance == TEAM_ALLIANCE)
						creature->UpdateEntry(NPC_JAINA_PART2);
					NPC_LeaderSecondGUID = creature->GetGUID();
					break;
				case NPC_LORALEN:
					if (teamIdInInstance == TEAM_ALLIANCE)
						creature->UpdateEntry(NPC_ELANDRA);
					if (!NPC_GuardFirstGUID)
					{
						NPC_GuardFirstGUID = creature->GetGUID();
						if (m_auiEncounter[0] == DONE && m_auiEncounter[1] == DONE)
							creature->SetVisible(false);
					}
					break;
				case NPC_KALIRA:
					if (teamIdInInstance == TEAM_ALLIANCE)
						creature->UpdateEntry(NPC_KORELN);
					if (!NPC_GuardSecondGUID)
					{
						NPC_GuardSecondGUID = creature->GetGUID();
						if (m_auiEncounter[0] == DONE && m_auiEncounter[1] == DONE)
							creature->SetVisible(false);
					}
					break;
			}
		}

		void HandleOutro()
		{
			if (!NPC_LeaderSecondGUID || !instance->GetCreature(NPC_LeaderSecondGUID))
				if (Creature* leader = instance->SummonCreature(NPC_SYLVANAS_PART2, outroSpawnPoint))
					if (Creature* boss = instance->GetCreature(NPC_DevourerGUID))
					{
						float angle = boss->GetAngle(leader);
						leader->GetMotionMaster()->MovePoint(1, boss->GetPositionX()+10.0f*cos(angle), boss->GetPositionY()+10.0f*sin(angle), boss->GetPositionZ());
					}

			for (int8 i = 0; outroPositions[i].entry[teamIdInInstance] != 0; ++i)
				if (Creature* summon = instance->SummonCreature(outroPositions[i].entry[teamIdInInstance], outroPositions[i].startPosition))
					summon->GetMotionMaster()->MovePath(outroPositions[i].pathId, false);
		}

		void SetData(uint32 type, uint32 data)
		{
			switch(type)
			{
				case DATA_BRONJAHM:
					m_auiEncounter[type] = data;
					break;
				case DATA_DEVOURER:
					m_auiEncounter[type] = data;
					if (m_auiEncounter[0] == DONE && m_auiEncounter[1] == DONE)
						HandleOutro();
					break;
			}

			if (data == DONE)
				SaveToDB();
		}

		uint64 GetData64(uint32 type) const
		{
			switch (type)
			{
				case DATA_BRONJAHM:	return NPC_BronjahmGUID;
			}

			return 0;
		}

		bool CheckAchievementCriteriaMeet(uint32 criteria_id, Player const* source, Unit const* target = NULL, uint32 miscvalue1 = 0)
		{
			switch(criteria_id)
			{
				case 12752: // Soul Power
					if( Creature* c = instance->GetCreature(NPC_BronjahmGUID) )
					{
						std::list<Creature*> L;
						uint8 count = 0;
						c->GetCreaturesWithEntryInRange(L, 200.0f, 36535); // find all Corrupted Soul Fragment (36535)
						for( std::list<Creature*>::const_iterator itr = L.begin(); itr != L.end(); ++itr )
							if( (*itr)->IsAlive() )
								++count;
						return (count >= 4);
					}
					break;
				case 12976:
					if( Creature* c = instance->GetCreature(NPC_DevourerGUID) )
						return (bool)c->AI()->GetData(1);
					break;
			}
			return false;
		}

		std::string GetSaveData()
		{
			OUT_SAVE_INST_DATA;

			std::ostringstream saveStream;
			saveStream << "F S " << m_auiEncounter[0] << ' ' << m_auiEncounter[1];
			str_data = saveStream.str();

			OUT_SAVE_INST_DATA_COMPLETE;
			return str_data;
		}

		void Load(const char* in)
		{
			if (!in)
			{
				OUT_LOAD_INST_DATA_FAIL;
				return;
			}

			OUT_LOAD_INST_DATA(in);

			char dataHead1, dataHead2;
			uint32 data0, data1;

			std::istringstream loadStream(in);
			loadStream >> dataHead1 >> dataHead2 >> data0 >> data1;

			if (dataHead1 == 'F' && dataHead2 == 'S')
			{
				m_auiEncounter[0] = data0;
				m_auiEncounter[1] = data1;

				for (uint8 i = 0; i < MAX_ENCOUNTER; ++i)
					if (m_auiEncounter[i] == IN_PROGRESS)
						m_auiEncounter[i] = NOT_STARTED;
			}
			else OUT_LOAD_INST_DATA_FAIL;

			OUT_LOAD_INST_DATA_COMPLETE;
		}
	};
};

void AddSC_instance_forge_of_souls()
{
	new instance_forge_of_souls();
}
